
#include <string.h>
#include "Card.h"
#include "CardPrivate.h"
#include "WCIPrivate.h"
#include "CardMemPrivate.h"
#include "CardMem.h"
#include "ISO14443p3a.h"

static MemCard_T mifareCard;
static const MemCardOps_T MifareOps;
static MifareInfo_T mifareInfo;


static Card_T * Card_Mifare_Create(WCI * wci)
{
	Card_T * card = (Card_T *) &mifareCard;

	card->type = Card_T_Mifare;
	card->wci = wci;
	card->ops = &MifareOps;
	card->pdata = (void *) &mifareInfo;
	return card;
}


static void Card_Mifare_Destroy(Card_T * card)
{
	(void)card;
}


const CardFactory_T mifareCardFactory =
{
	.create = Card_Mifare_Create, 
	.destroy = Card_Mifare_Destroy, 
};


static int Mifare_Setup(Card_T * card, void * param)
{
	MifareInfo_T * pdata = (MifareInfo_T *)	card->pdata;
	ISO14443AInfo_T * info = (ISO14443AInfo_T *)param;
	uint8_t offset = info->ulen > 4 ? 4: 0;

	memcpy(pdata->uid, info->uid + offset, 4);
	pdata->ulen = 4;
	return 0;
}


static int Mifare_Authen(Card_T * card, void * param, uint8_t * key, uint8_t klen)
{
	WCI * wci = card->wci;
	MifareInfo_T * info = (MifareInfo_T *)card->pdata;
	MifareAuthParam_T * pa = (MifareAuthParam_T *)param;
	MfAuthParam_T mfauthparam;
	
	WciTime_T xtime = {
		WaitTime_Ms(3, 0), 0
	};
	int ret;
	
	mfauthparam.keyType = (pa->keyType == 0) ? 0x60: 0x61;
	mfauthparam.block = pa->sector * 4;
	memcpy(mfauthparam.uid, info->uid, info->ulen);
	memcpy(mfauthparam.keys, key, klen);
	
#if 0
	WCI_ClearFifo(wci);
	WCI_WriteFifo(wci, & (uint8_t) { (pa->keyType == 0) ? 0x60: 0x61 }, 1);
	WCI_WriteFifo(wci, & (uint8_t) { pa->sector * 4 }, 1);

	//		WCI_WriteFifo(wci, &pa->sector, 1);
	WCI_WriteFifo(wci, key, 6);
	WCI_WriteFifo(wci, info->uid, info->ulen);
#endif 
	ret = WCI_Command(wci, WCI_Cmd_Authen, &xtime, &mfauthparam);
	return ret;
}


static int Mifare_ReadBlock(Card_T * card, uint32_t block, uint8_t * buf, uint16_t len)
{
	unsigned char cmd[2] = {
		0x30, block
	};
//		int ret;
	unsigned int rlen;

	if (len != 16) {
		return - 1;
	}

	return WCI_Exchange(card->wci, cmd, sizeof(cmd), buf, &rlen, 16, WaitTime_Ms(3, 0), 0);
}


static int Mifare_WriteBlock(Card_T * card, uint32_t block, uint8_t * wbuf, uint16_t wlen)
{
	WCI * wci = card->wci;
	unsigned char txBuf[2] = {
		0xA0, (uint8_t)
		block
	};
	unsigned char rxBuf[2] = {
		0
	};
	unsigned int rLen = 0;
	unsigned int rbits = 0;
	unsigned int rmax = 2;
	int ret;

	ret = WCI_ExchangeBit(wci, txBuf, sizeof(txBuf), 0, 
		rxBuf, &rLen, &rbits, rmax, 
		WaitTime_Ms(1, 0), 0);

	if (rbits != 4 || (rxBuf[0] != 0x0A)) {
		return - 1;
	}

	rxBuf[0] = 0;
	rbits = 0;
	ret = WCI_ExchangeBit(wci, wbuf, wlen, 0, 
		rxBuf, &rLen, &rbits, rmax, 
		WaitTime_Ms(10, 0), 0);

	if (rbits != 4 || (rxBuf[0] != 0x0A)) {
		return - 1;
	}
	(void)ret;
	return 0;
}


static int Mifare_BlockInc(Card_T * card, uint8_t block, uint8_t val[4])
{
	unsigned char txBuf[2];
	unsigned char rxBuf[2];
	unsigned int rLen = 0;
	int result;

	rxBuf[0] = 0;
	txBuf[0] = 0xC1;								// C1 å¢å€¼æŒ‡ä»?
	txBuf[1] = block;								//å—åœ°å€
	result = WCI_Exchange(card->wci, txBuf, sizeof(txBuf), rxBuf, &rLen, 2, WaitTime_Ms(5, 0), 0);

	if ((result == WCI_S_Timeout) || ((rxBuf[0] &0x0F) != 0x0A)) { //å¦‚æœæœªæ¥æ”¶åˆ°0x0Aï¼Œè¡¨ç¤ºæ— ACK
		return - 1;
	}

	rxBuf[0] = 0;
	WCI_Exchange(card->wci, val, 4, rxBuf, &rLen, 2, WaitTime_Ms(15, 0), 0);
	return 0;
}


static int Mifare_BlockDec(Card_T * card, uint8_t block, uint8_t val[4])
{
	unsigned char txBuf[2];
	unsigned char rxBuf[2];
	unsigned int rLen = 0;
	int result;

	rxBuf[0] = 0;
	txBuf[0] = 0xC0;								// C0 å‡å€¼æŒ‡ä»?
	txBuf[1] = block;								//å—åœ°å€
	result = WCI_Exchange(card->wci, txBuf, sizeof(txBuf), rxBuf, &rLen, 2, WaitTime_Ms(5, 0), 0);

	if ((result == WCI_S_Timeout) || ((rxBuf[0] &0x0F) != 0x0A)) { //å¦‚æœæœªæ¥æ”¶åˆ°0x0Aï¼Œè¡¨ç¤ºæ— ACK
		return - 1;
	}

	rxBuf[0] = 0;
	WCI_Exchange(card->wci, val, 4, rxBuf, &rLen, 2, WaitTime_Ms(15, 0), 0);
	return 0;
}


static int Mifare_BlockRestore(Card_T * card, unsigned char block)
{
	unsigned char txBuf[2];
	unsigned char rxBuf[2];
	unsigned int rLen = 0;
	int result;

	rxBuf[0] = 0;
	txBuf[0] = 0xC2;								// 
	txBuf[1] = block;								//å—åœ°å€
	result = WCI_Exchange(card->wci, txBuf, sizeof(txBuf), rxBuf, &rLen, 2, WaitTime_Ms(5, 0), 0);

	if ((result == WCI_S_Timeout) || ((rxBuf[0] &0x0F) != 0x0A)) { //å¦‚æœæœªæ¥æ”¶åˆ°0x0Aï¼Œè¡¨ç¤ºæ— ACK
		return - 1;
	}

	rxBuf[0] = 0;
	memset(txBuf, 0, sizeof(txBuf));
	WCI_Exchange(card->wci, txBuf, sizeof(txBuf), rxBuf, &rLen, 2, WaitTime_Ms(15, 0), 0);
	return 0;
}


static int Mifare_BlockTransfer(Card_T * card, uint8_t block)
{
	unsigned char txBuf[2];
	unsigned char rxBuf[2];
	unsigned int rLen = 0;
	int result;

	rxBuf[0] = 0;
	txBuf[0] = 0xB0;								// 
	txBuf[1] = block;								//å—åœ°å€
	result = WCI_Exchange(card->wci, txBuf, sizeof(txBuf), rxBuf, &rLen, 2, WaitTime_Ms(15, 0), 0);

	if ((result == WCI_S_Timeout) || ((rxBuf[0] &0x0F) != 0x0A)) { //å¦‚æœæœªæ¥æ”¶åˆ°0x0Aï¼Œè¡¨ç¤ºæ— ACK
		return - 1;
	}

	return result;
}


static int Mifare_BlockSet(Card_T * card, uint8_t block, uint8_t val[4])
{
	unsigned char block_data[16];

	block_data[0] = val[3];
	block_data[1] = val[2];
	block_data[2] = val[1];
	block_data[3] = val[0];
	block_data[4] = ~val[3];
	block_data[5] = ~val[2];
	block_data[6] = ~val[1];
	block_data[7] = ~val[0];
	block_data[8] = val[3];
	block_data[9] = val[2];
	block_data[10] = val[1];
	block_data[11] = val[0];
	block_data[12] = block;
	block_data[13] = ~block;
	block_data[14] = block;
	block_data[15] = ~block;
	return Mifare_WriteBlock(card, block, block_data, sizeof(block_data));
}


static int Mifare_Control(Card_T * card, uint8_t ctrl, void * param, 
	void * cbuf, uint16_t clen, void * rbuf, uint16_t * rlen)
{
	int ret = 0;
	uint8_t block = * (uint8_t *) param;
	switch (ctrl)
	{
		//		case Card_Ctrl_MFAuth:
		//			//ret = Mifare_Authen(card, ctrl, cbuf, clen, rbuf, rlen);
		//			break;
		//		case Card_Ctrl_MFRead:
		//			ret = Mifare_ReadBlock(card, cbuf[0], rbuf, rlen);
		//			break;
		//		case Card_Ctrl_MFWrite:
		//			ret = Mifare_WriteBlock(card, cbuf[0], &cbuf[1], clen - 1);
		//			break;
		case Card_Ctrl_MFInc:
			ret = Mifare_BlockInc(card,block, cbuf);
			if(ret == 0){
				ret = Mifare_BlockTransfer(card, block);
			}
			break;

		case Card_Ctrl_MFDec:
			ret = Mifare_BlockDec(card, block, cbuf);
			if(ret == 0){
				ret = Mifare_BlockTransfer(card, block);
			}
			break;

		case Card_Ctrl_MFRestore:
			ret = Mifare_BlockRestore(card, block);
			if(ret == 0){
				ret = Mifare_BlockTransfer(card, block);
			}
			break;

		case Card_Ctrl_Transfer:
			ret = Mifare_BlockTransfer(card, block);
			break;

		case Card_Ctrl_SetValue:
			ret = Mifare_BlockSet(card, block, (uint8_t *) cbuf);
			break;

		default:
			ret = -1;
	}

	return ret;
}


const MemCardOps_T MifareOps =
{
	.authen = Mifare_Authen, 
	.read = Mifare_ReadBlock, 
	.write = Mifare_WriteBlock, 
	.setup = Mifare_Setup, 
	.control = Mifare_Control,
};


// const Protocol mifareProtocol = {
//	.deactivate = ProtocolCL_Deselect,
//	.exchange = ProtocolCL_Exchange,
//	.setup = ProtocolCL_Setup,
//	.teardown = ProtocolCL_Teardown,
//	.config = ProtocolCL_Config,
//	.check = ProtocolCL_Check,
//	.control = MifareProtocol_Control,
// };
//	
// static void MifareProtocol_Init(void) {
//	Protocol_Register(PROTO_T_Mifare, &mifareProtocol);
// }
// 
// INIT_FUNC(MifareProtocol_Init);
